<?php

declare(strict_types=1);

namespace App\Controller;

use App\Job\HeartEvent;
use App\Job\IotEvent;
use App\Model\Normal;
use Hyperf\AsyncQueue\Driver\DriverFactory;
use Hyperf\Context\ApplicationContext;
use Hyperf\Contract\OnCloseInterface;
use Hyperf\Contract\OnReceiveInterface;
use Hyperf\Logger\LoggerFactory;
use Psr\Log\LoggerInterface;
use Swoole\Timer;
use Swoole\Server as SwooleServer;

class TcpServer implements OnReceiveInterface, OnCloseInterface
{
    protected LoggerInterface $logger;

    // 添加连接状态跟踪
    private static array $connections = [];
    private static array $buffer = []; // 添加缓冲区
    private static ?int $diagnosticTimerId = null;
    private static ?int $cleanupTimerId = null;
    private const STATE_CONNECTED = 'connected';
    private const STATE_CLOSING = 'closing';
    private const STATE_CLOSED = 'closed';

    public function __construct(LoggerFactory $loggerFactory)
    {
        $this->logger = $loggerFactory->get('log', 'device');
    }

    /**
     * 处理连接建立事件
     */
    public function onConnect($server, int $fd, int $reactorId): void
    {
        try {
            // 初始化连接状态和缓冲区
            self::$connections[$fd] = [
                'state' => self::STATE_CONNECTED,
                'connect_time' => microtime(true),
                'last_activity' => microtime(true),
                'charger_id' => null,
                'reactor_id' => $reactorId,
                'remote_ip' => $server->getClientInfo($fd)['remote_ip'] ?? 'unknown'
            ];
            self::$buffer[$fd] = ''; // 初始化缓冲区

            Normal::logger(sprintf(
                "Connection established - FD:%d Reactor:%d IP:%s",
                $fd,
                $reactorId,
                self::$connections[$fd]['remote_ip']
            ), 'notify-event');
        } catch (\Exception $e) {
            Normal::logger(sprintf(
                "Connect error - FD:%d Error:%s Trace:%s",
                $fd,
                $e->getMessage(),
                $e->getTraceAsString()
            ), 'notify-event');
        }
    }

    /**
     * 处理数据接收事件
     */
    public function onReceive($server, int $fd, int $reactorId, string $data): void
    {
        try {
            // 将新数据添加到缓冲区
            if (!isset(self::$buffer[$fd])) {
                self::$buffer[$fd] = '';
            }
            self::$buffer[$fd] .= $data;

            // 循环处理完整数据包
            while (strlen(self::$buffer[$fd]) >= 6) {
                // 获取数据包长度
                $length = unpack('n', substr(self::$buffer[$fd], 4, 2))[1];
                $packetLen = 6 + $length + 2; // 头部6字节 + 数据长度 + CRC2字节

                // 检查缓冲区中是否有完整数据包
                if (strlen(self::$buffer[$fd]) >= $packetLen) {
                    // 提取完整数据包
                    $packetData = substr(self::$buffer[$fd], 0, $packetLen);
                    // 从缓冲区中移除已处理的数据
                    self::$buffer[$fd] = substr(self::$buffer[$fd], $packetLen);

                    // 处理单个数据包
                    $this->processSinglePacket($server, $fd, $reactorId, $packetData);
                } else {
                    // 缓冲区中没有完整数据包，等待更多数据
                    break;
                }
            }
        } catch (\Exception $e) {
            Normal::logger(sprintf(
                "Process error - FD:%d Error:%s Trace:%s",
                $fd,
                $e->getMessage(),
                $e->getTraceAsString()
            ), 'notify-event');
        }
    }

    /**
     * 处理单个数据包
     */
    private function processSinglePacket($server, int $fd, int $reactorId, string $data): void
    {
        $packet = $this->parsePacket($data, $fd);
        if (!$packet) {
            Normal::logger(sprintf(
                "Parse error - FD:%d Error",
                $fd
            ), 'notify-event');
            return;
        }

        list($command, $body, $seq, $length) = $packet;

        // 分发到不同处理函数
        switch ($command) {
            case 0x01: // 登录请求
                $this->handleLogin($server, $fd, $body, $seq);
                break;
            case 0x02: // 心跳请求
                $this->handleHeartbeat($server, $fd, $body, $seq);
                break;
            case 0x03: // 充电进度上报
                $this->handleChargeProgress($server, $fd, $body, $seq);
                break;
            case 0x04: // 远程启动充电响应
                $this->handleRemoteStartResponse($server, $fd, $body, $seq);
                break;
            case 0x05: // 远程结束充电响应
                $this->handleRemoteStopResponse($server, $fd, $body, $seq);
                break;
            case 0x06: // 上传充电记录
                $this->handleChargeRecord($server, $fd, $body, $seq);
                break;
            case 0x09: // 告警上报
                $this->handleAlarm($server, $fd, $body, $seq);
                break;
            case 0x0A: // 重启响应
                $this->handleRestartResponse($server, $fd, $body, $seq);
                break;
            case 0x0D: // 设备参数设置响应
                $this->handleDeviceParameterResponse($server, $fd, $body, $seq);
                break;
            case 0x0C: // 设备参数读取响应
                $this->handleDeviceParameterReadResponse($server, $fd, $body, $seq);
                break;
            case 0x0E: // 电池状态信息上报
                $this->handleBatteryStatus($server, $fd, $body, $seq);
                break;
            default:
                Normal::logger(sprintf(
                    "Unknown command 0x%02X from FD:%d",
                    $command,
                    $fd
                ), 'notify-event');
                break;
        }
    }

    /**
     * 处理连接关闭事件
     */
    public function onClose($server, int $fd, int $reactorId): void
    {
        try {
            // 标记连接为关闭中状态
            if (isset(self::$connections[$fd])) {
                self::$connections[$fd]['state'] = self::STATE_CLOSING;
            }

            // 清理缓冲区
            if (isset(self::$buffer[$fd])) {
                unset(self::$buffer[$fd]);
            }

            $clientInfo = $server->getClientInfo($fd);
            $errorCode = swoole_last_error();
            $errorMsg = swoole_strerror($errorCode);

            $duration = 0;
            $lastActivity = 0;
            $chargerId = 'unknown';

            if (isset(self::$connections[$fd])) {
                $duration = microtime(true) - self::$connections[$fd]['connect_time'];
                $lastActivity = microtime(true) - self::$connections[$fd]['last_activity'];
                $chargerId = self::$connections[$fd]['charger_id'] ?? 'unknown';
            }

            Normal::logger(sprintf(
                "Connection closed - FD:%d ChargerID:%s Duration:%.2fs Inactive:%.2fs Reactor:%d Error:%d(%s) Info:%s",
                $fd,
                $chargerId,
                $duration,
                $lastActivity,
                $reactorId,
                $errorCode,
                $errorMsg,
                json_encode($clientInfo, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
            ), 'notify-event');

            $driver = ApplicationContext::getContainer()->get(DriverFactory::class)->get('iot-event');
            $driver->push(new IotEvent($fd, 'close', [
                'reason' => 'server_close',
                'client_info' => $clientInfo ?? null,
                'error_code' => $errorCode,
                'error_msg' => $errorMsg,
                'duration' => $duration,
                'inactive_time' => $lastActivity
            ]));

            // 标记连接为已关闭并清理
            if (isset(self::$connections[$fd])) {
                self::$connections[$fd]['state'] = self::STATE_CLOSED;
                unset(self::$connections[$fd]);
            }
        } catch (\Exception $e) {
            Normal::logger(sprintf(
                "Close error - FD:%d Error:%s Trace:%s",
                $fd,
                $e->getMessage(),
                $e->getTraceAsString()
            ), 'notify-event');
        }
    }

    /**
     * Worker停止时调用 (通过ON_WORKER_STOP回调)
     */
    public static function stopDiagnostics(SwooleServer $server): void
    {
        try {
            Normal::logger("Worker stopping - Cleaning up resources", 'notify-event');

            // 清理诊断定时器
            if (self::$diagnosticTimerId !== null) {
                Timer::clear(self::$diagnosticTimerId);
                self::$diagnosticTimerId = null;
                Normal::logger("Diagnostic timer cleared", 'notify-event');
            }

            // 清理过期连接检查定时器
            if (self::$cleanupTimerId !== null) {
                Timer::clear(self::$cleanupTimerId);
                self::$cleanupTimerId = null;
                Normal::logger("Cleanup timer cleared", 'notify-event');
            }

            // 记录连接清理前的状态
            $connectionCount = count(self::$connections);
            if ($connectionCount > 0) {
                Normal::logger(sprintf(
                    "Cleaning up %d connections before worker stop",
                    $connectionCount
                ), 'notify-event');

                // 清理所有连接状态和缓冲区
                self::$connections = [];
                self::$buffer = []; // 清理缓冲区
            }

            Normal::logger("Worker stop cleanup completed", 'notify-event');
        } catch (\Exception $e) {
            Normal::logger(sprintf(
                "Error during worker stop cleanup: %s",
                $e->getMessage()
            ), 'notify-event');
        }
    }

    /**
     * 解析二进制协议包
     */
    private function parsePacket(string $data, int $fd): ?array
    {
        $len = strlen($data);
        if ($len < 6) {
            Normal::logger(sprintf(
                "Invalid packet - FD:%d Reason:Too short (%d bytes)",
                $fd,
                $len
            ), 'notify-event');
            return null;
        }

        $startByte = ord($data[0]);
        if ($startByte !== 0x68) {
            Normal::logger(sprintf(
                "Invalid packet - FD:%d Reason:Bad start byte 0x%02X",
                $fd,
                $startByte
            ), 'notify-event');
            return null;
        }

        $command = ord($data[1]);
        $seq = unpack('n', substr($data, 2, 2))[1];
        $length = unpack('n', substr($data, 4, 2))[1];

        if ($len < (6 + $length + 2)) {
            Normal::logger(sprintf(
                "Invalid packet - FD:%d Reason:Incomplete (expected:%d actual:%d)",
                $fd,
                6 + $length + 2,
                $len
            ), 'notify-event');
            return null;
        }

        $body = substr($data, 6, $length);
        $receivedCrc = unpack('n', substr($data, -2))[1];
        $calculatedCrc = $this->calculateCrc(substr($data, 1, -2));

        if ($receivedCrc !== $calculatedCrc) {
            Normal::logger(sprintf(
                "CRC failed - FD:%d Command:0x%02X Expected:0x%04X Actual:0x%04X",
                $fd,
                $command,
                $receivedCrc,
                $calculatedCrc
            ), 'notify-event');
            return null;
        }

        return [$command, $body, $seq, $length];
    }

    /**
     * XMODEM CRC16校验 (多项式0x1021)
     */
    private function calculateCrc(string $data): int
    {
        $crc = 0x0000;
        $polynomial = 0x1021;

        for ($i = 0; $i < strlen($data); $i++) {
            $byte = ord($data[$i]);
            for ($j = 0; $j < 8; $j++) {
                $bit = (($byte >> (7 - $j)) & 1) === 1;
                $c15 = (($crc >> 15) & 1) === 1;
                $crc <<= 1;
                if ($c15 ^ $bit) {
                    $crc ^= $polynomial;
                }
            }
        }

        return $crc & 0xFFFF;
    }

    /**
     * 构建应答包
     */
    private function buildResponse(int $command, int $seq, string $body): string
    {
        $header = chr(0x68) . chr($command) . pack('n', $seq) . pack('n', strlen($body));
        $raw = $header . $body;
        $crc = $this->calculateCrc(substr($raw, 1));
        $response = $raw . pack('n', $crc);

        // 记录应答的完整报文
        Normal::logger(sprintf(
            "Response Packet - Command:0x%02X Seq:%d Data:%s",
            $command,
            $seq,
            bin2hex($response)
        ), 'notify-event');

        return $response;
    }


    private function encodeBCDDateTime(string $datetimeStr): string
    {
        $result = '';
        // 将每两个数字转换为一个BCD字节
        for ($i = 0; $i < strlen($datetimeStr); $i += 2) {
            $high = intval($datetimeStr[$i]);
            $low = intval($datetimeStr[$i + 1]);
            $result .= chr(($high << 4) | $low);
        }
        return $result;
    }

    /**
     * 将设备号二进制数据转换为字符串
     * @param string $binaryId 8字节二进制数据
     * @return string 设备号字符串
     */
    private function parseChargerId(string $binaryId): string
    {
        $result = '';

        // 按BCD格式解析8字节数据
        for ($i = 0; $i < 8; $i++) {
            $byte = ord($binaryId[$i]);

            // 高4位
            $high = ($byte >> 4) & 0x0F;
            // 低4位
            $low = $byte & 0x0F;

            // 确保是有效的BCD码(0-9)
            if ($high <= 9 && $low <= 9) {
                $result .= $high . $low;
            } else {
                // 如果不是有效的BCD码，使用默认值
                $result .= '00';
            }
        }

        // 去除左侧的0，但至少保留一位数字
        $result = ltrim($result, '0');
        if ($result === '') {
            $result = '0';
        }

        // 记录转换日志
        Normal::logger(sprintf(
            "设备号解析: 输入(HEX)=%s, 输出=%s",
            bin2hex($binaryId),
            $result
        ), 'notify-event');

        return $result;
    }

    /**
     * 处理登录请求 (0x01)
     */
    private function handleLogin($server, int $fd, string $body, int $seq): void
    {
        try {
            // 1. 获取桩编号的二进制数据（8字节）
            $binaryChargerId = substr($body, 0, 8);

            // 2. 解析为字符串
            $chargerId = $this->parseChargerId($binaryChargerId);

            // 3. 解析其他字段
            $gunCount = ord($body[8]);
            $protocolVersion = unpack('n', substr($body, 9, 2))[1];
            $hardwareVersion = unpack('n', substr($body, 11, 2))[1];
            $softwareVersion = unpack('n', substr($body, 13, 2))[1];
            $iccid = substr($body, 15, 20);

            // 4. 记录登录信息
            Normal::logger(sprintf(
                "Login - FD:%d ID:%s Guns:%d Versions:Proto:%d Hardware:%d Software:%d ICCID:%s",
                $fd,
                $chargerId,
                $gunCount,
                $protocolVersion,
                $hardwareVersion,
                $softwareVersion,
                $iccid
            ), 'notify-event');

            // 5. 构造登录成功响应（0x81）
            $responseBody = $binaryChargerId . chr(0) . $this->encodeBCDDateTime(date('ymdHis'));
            $response = $this->buildResponse(0x81, $seq, $responseBody);
            $server->send($fd, $response);

            // 6. 记录设备ID到连接状态
            if (isset(self::$connections[$fd])) {
                self::$connections[$fd]['charger_id'] = $chargerId;
            }

            // 7. 异步处理设备上线
            $driver = ApplicationContext::getContainer()->get(DriverFactory::class)->get('iot-event');
            $driver->push(new IotEvent($fd, 'login', [
                'charger_id' => $chargerId,
                'channel' => $gunCount,
                'versions' => [
                    'protocol' => $protocolVersion,
                    'hardware' => $hardwareVersion,
                    'software' => $softwareVersion
                ],
                'card_no' => $iccid
            ]));

        } catch (\Exception $e) {
            Normal::logger(sprintf(
                "Login processing error - FD:%d Error:%s Trace:%s",
                $fd,
                $e->getMessage(),
                $e->getTraceAsString()
            ), 'notify-event');
        }
    }

    /**
     * 处理心跳请求 (0x02)
     */
    private function handleHeartbeat($server, int $fd, string $body, int $seq): void
    {
        try {
            // 1. 获取桩编号的二进制数据（8字节）
            $binaryChargerId = substr($body, 0, 8);

            // 2. 解析为字符串
            $chargerId = $this->parseChargerId($binaryChargerId);

            // 3. 解析其他字段
            $gunCount = ord($body[8]);
            $gunStatus = array_map('ord', str_split(substr($body, 9, $gunCount)));
            $signalStrength = ord($body[9 + $gunCount]);
            $temperature = unpack('n', substr($body, 10 + $gunCount, 2))[1];

            // 4. 记录心跳信息
            Normal::logger(sprintf(
                "Heartbeat - FD:%d ID:%s Signal:%d Temp:%.1f℃ Status:%s",
                $fd,
                $chargerId,
                $signalStrength,
                ($temperature / 100) - 50,
                implode(',', $gunStatus)
            ), 'notify-event');

            // 5. 构造心跳响应（0x82）
            $responseBody = $binaryChargerId . $this->encodeBCDDateTime(date('ymdHis'));
            $response = $this->buildResponse(0x82, $seq, $responseBody);
            $server->send($fd, $response);

            // 6. 异步处理心跳
            $driver = ApplicationContext::getContainer()->get(DriverFactory::class)->get('iot-event');
            $driver->push(new HeartEvent($fd, 'heartbeat', [
                'charger_id' => $chargerId,
                'signal' => $signalStrength,
                'temperature' => ($temperature / 100) - 50,
                'gun_status' => $gunStatus,
                'channel' => $gunCount
            ]));

        } catch (\Exception $e) {
            Normal::logger(sprintf(
                "Heartbeat processing error - FD:%d Error:%s Trace:%s",
                $fd,
                $e->getMessage(),
                $e->getTraceAsString()
            ), 'notify-event');
        }
    }

    /**
     * 处理充电进度上报 (0x03)
     */
    private function handleChargeProgress($server, int $fd, string $body, int $seq): void
    {
        try {
            // 1. 获取桩编号的二进制数据（8字节）
            $binaryChargerId = substr($body, 0, 8);

            // 2. 解析为字符串
            $chargerId = $this->parseChargerId($binaryChargerId);

            // 3. 解析其他字段
            $gunNo = ord($body[8]);
            $orderId = unpack('J', substr($body, 9, 8))[1];
            $voltage = unpack('n', substr($body, 17, 2))[1] / 100;
            $current = unpack('n', substr($body, 19, 2))[1] / 100;
            $power = unpack('n', substr($body, 21, 2))[1];
            $duration = unpack('n', substr($body, 25, 2))[1];
            $energy = unpack('n', substr($body, 27, 2))[1] / 100;

            // 4. 记录充电信息
            Normal::logger(sprintf(
                "ChargeProgress - FD:%d ID:%s Gun:%d Order:%d %.1fV/%.1fA/%dW Duration:%ds Energy:%.2fkWh",
                $fd,
                $chargerId,
                $gunNo,
                $orderId,
                $voltage,
                $current,
                $power,
                $duration,
                $energy
            ), 'notify-event');

            // 5. 构造响应（0x83）
            $response = $this->buildResponse(0x83, $seq, $binaryChargerId);
            $server->send($fd, $response);

            // 6. 异步处理充电数据
            $driver = ApplicationContext::getContainer()->get(DriverFactory::class)->get('iot-event');
            $driver->push(new IotEvent($fd, 'charge_progress', [
                'sn' => $chargerId,
                'channel_number' => $gunNo,
                'number' => $orderId,
                'volt' => $voltage,
                'curr' => $current,
                'power' => $power,
                'duration' => $duration,
                'elec' => $energy
            ]));

        } catch (\Exception $e) {
            Normal::logger(sprintf(
                "Charge progress processing error - FD:%d Error:%s Trace:%s",
                $fd,
                $e->getMessage(),
                $e->getTraceAsString()
            ), 'notify-event');
        }
    }

    /**
     * 处理远程启动充电响应 (0x04)
     */
    private function handleRemoteStartResponse($server, int $fd, string $body, int $seq): void
    {
        try {
            if (strlen($body) < 18) {
                Normal::logger(sprintf(
                    "Invalid RemoteStartResponse - FD:%d Body too short (%d bytes)",
                    $fd,
                    strlen($body)
                ), 'notify-event');
                return;
            }

            // 1. 获取桩编号的二进制数据（8字节）
            $binaryChargerId = substr($body, 0, 8);

            // 2. 解析为字符串
            $chargerId = $this->parseChargerId($binaryChargerId);

            // 3. 解析其他字段
            $gunNo = ord($body[8]);
            $orderId = unpack('J', substr($body, 9, 8))[1];
            $result = ord($body[17]);

            $resultText = match($result) {
                0 => '启动成功',
                1 => '充电中',
                2 => '未插枪',
                3 => '枪号错误',
                4 => '枪故障',
                5 => '桩故障',
                6 => '其他原因',
                default => '未知错误'
            };

            // 4. 记录响应信息
            Normal::logger(sprintf(
                "RemoteStartResponse - FD:%d ID:%s Gun:%d Order:%d Result:%d(%s)",
                $fd,
                $chargerId,
                $gunNo,
                $orderId,
                $result,
                $resultText
            ), 'notify-event');

            // 5. 异步处理远程启动响应业务
            $driver = ApplicationContext::getContainer()->get(DriverFactory::class)->get('iot-event');
            $driver->push(new IotEvent($fd, 'start', [
                'sn' => $chargerId,
                'channel_number' => $gunNo,
                'number' => $orderId,
                'result' => $result,
                'result_text' => $resultText
            ]));
        } catch (\Exception $e) {
            Normal::logger(sprintf(
                "Remote start response processing error - FD:%d Error:%s Trace:%s",
                $fd,
                $e->getMessage(),
                $e->getTraceAsString()
            ), 'notify-event');
        }
    }

    /**
     * 处理上传充电记录 (0x06)
     */
    private function handleChargeRecord($server, int $fd, string $body, int $seq): void
    {
        try {
            if (strlen($body) < 20) {
                Normal::logger(sprintf(
                    "Invalid ChargeRecord - FD:%d Body too short (%d bytes)",
                    $fd,
                    strlen($body)
                ), 'notify-event');
                return;
            }

            // 1. 获取桩编号的二进制数据（8字节）
            $binaryChargerId = substr($body, 0, 8);

            // 2. 解析为字符串
            $chargerId = $this->parseChargerId($binaryChargerId);

            // 3. 解析其他字段
            $gunNo = ord($body[8]);
            $orderId = unpack('J', substr($body, 9, 8))[1];
            $endReason = ord($body[17]);
            $duration = unpack('n', substr($body, 18, 2))[1];
            $energy = unpack('n', substr($body, 20, 2))[1] / 100;
            $maxPower = unpack('n', substr($body, 22, 2))[1];

            // 4. 结束原因文本映射 (根据附录B)
            $endReasonText = $this->getChargeEndReasonText($endReason);

            // 5. 记录充电记录信息
            Normal::logger(sprintf(
                "ChargeRecord - FD:%d ID:%s Gun:%d Order:%d Reason:0x%02X(%s) Duration:%ds Energy:%.2fkWh Power:%dW",
                $fd,
                $chargerId,
                $gunNo,
                $orderId,
                $endReason,
                $endReasonText,
                $duration,
                $energy,
                $maxPower
            ), 'notify-event');

            // 6. 构造响应包 (0x86)
            $responseBody = $binaryChargerId . chr($gunNo) . pack('J', $orderId) . chr(0) . pack('N', 0);
            $response = $this->buildResponse(0x86, $seq, $responseBody);
            $server->send($fd, $response);

            // 7. 异步处理充电记录
            $driver = ApplicationContext::getContainer()->get(DriverFactory::class)->get('iot-event');
            $driver->push(new IotEvent($fd, 'stop', [
                'sn' => $chargerId,
                'channel_number' => $gunNo,
                'number' => $orderId,
                'stop_reason' => $endReason,
                'stop_reason_text' => $endReasonText,
                'duration' => $duration,
                'elec' => $energy,
                'power' => $maxPower
            ]));

        } catch (\Exception $e) {
            Normal::logger(sprintf(
                "Charge record processing error - FD:%d Error:%s Trace:%s",
                $fd,
                $e->getMessage(),
                $e->getTraceAsString()
            ), 'notify-event');
        }
    }


    private function getChargeEndReasonText(int $reasonCode): string
    {
        $reasonMap = [
            0x00 => '其他原因',
            0x01 => '充满停止',
            0x02 => '购买量用完停止',
            0x03 => '购买量用完结束',
            0x04 => '未插插座停止',
            0x05 => '充电过程中拔枪停止',
            0x06 => '过压停止',
            0x07 => '欠压停止',
            0x08 => '过温停止',
            0x09 => '计量异常停止',
            0x0A => '检测到烟雾停止',
            0x0B => '单路功率超限停止',
            0x0C => '整机功率超限停止',
            0x0D => '检测到消防告警停止'
        ];

        return $reasonMap[$reasonCode] ?? '未知原因';
    }

    /**
     * 处理告警上报 (0x09)
     */
    private function handleAlarm($server, int $fd, string $body, int $seq): void
    {
        try {
            // 1. 获取桩编号的二进制数据（8字节）
            $binaryChargerId = substr($body, 0, 8);
            // 2. 解析为字符串
            $chargerId = $this->parseChargerId($binaryChargerId);
            // 3. 解析其他字段
            $gunNo = ord($body[8]);
            $alarmCode = unpack('n', substr($body, 9, 2))[1];
            $alarmTime = substr($body, 11, 6); // 6字节BCD时间
            $alarmStatus = ord($body[17]);
            $alarmValue = unpack('n', substr($body, 18, 2))[1]; // 告警值，精度0.01

            // 4. 正确转换为可读时间 (BCD格式: YYMMDDHHMMSS)
            $year = sprintf('%02d%02d', (ord($alarmTime[0]) >> 4) & 0x0F, ord($alarmTime[0]) & 0x0F);
            $month = sprintf('%02d%02d', (ord($alarmTime[1]) >> 4) & 0x0F, ord($alarmTime[1]) & 0x0F);
            $day = sprintf('%02d%02d', (ord($alarmTime[2]) >> 4) & 0x0F, ord($alarmTime[2]) & 0x0F);
            $hour = sprintf('%02d%02d', (ord($alarmTime[3]) >> 4) & 0x0F, ord($alarmTime[3]) & 0x0F);
            $minute = sprintf('%02d%02d', (ord($alarmTime[4]) >> 4) & 0x0F, ord($alarmTime[4]) & 0x0F);
            $second = sprintf('%02d%02d', (ord($alarmTime[5]) >> 4) & 0x0F, ord($alarmTime[5]) & 0x0F);

            $formattedTime = sprintf(
                '20%s-%s-%s %s:%s:%s',
                $year,
                $month,
                $day,
                $hour,
                $minute,
                $second
            );

            // 5. 构造响应包 (0x89)
            $response = $this->buildResponse(0x89, $seq, $binaryChargerId);
            $server->send($fd, $response);

            // 6. 异步处理告警业务
            $driver = ApplicationContext::getContainer()->get(DriverFactory::class)->get('iot-event');
            $driver->push(new IotEvent($fd, 'alarm', [
                'charger_id' => $chargerId,
                'gun_no' => $gunNo,
                'alarm_code' => $alarmCode,
                'alarm_time' => $formattedTime,
                'alarm_status' => $alarmStatus,
                'alarm_value' => $alarmValue / 100 // 转换为实际值
            ]));
        } catch (\Exception $e) {
            $this->logger->error("Alarm processing failed", [
                'fd' => $fd,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
        }
    }

    /**
     * 处理远程结束充电响应 (0x05)
     * 充电桩对运营管理系统远程结束充电命令的回复
     */
    private function handleRemoteStopResponse($server, int $fd, string $body, int $seq): void
    {
        try {
            if (strlen($body) < 18) {
                Normal::logger(sprintf(
                    "Invalid RemoteStopResponse - FD:%d Body too short (%d bytes)",
                    $fd,
                    strlen($body)
                ), 'notify-event');
                return;
            }

            // 1. 获取桩编号的二进制数据（8字节）
            $binaryChargerId = substr($body, 0, 8);

            // 2. 解析为字符串
            $chargerId = $this->parseChargerId($binaryChargerId);

            // 3. 解析其他字段
            $gunNo = ord($body[8]);
            $orderId = unpack('J', substr($body, 9, 8))[1];
            $result = ord($body[17]);

            $resultText = match($result) {
                0 => '结束成功',
                1 => '枪号错误',
                2 => '该枪未充电',
                3 => '其他原因',
                default => '未知错误'
            };

            // 4. 记录响应信息
            Normal::logger(sprintf(
                "RemoteStopResponse - FD:%d ID:%s Gun:%d Order:%d Result:%d(%s)",
                $fd,
                $chargerId,
                $gunNo,
                $orderId,
                $result,
                $resultText
            ), 'notify-event');

            // 5. 异步处理远程结束响应业务
//            $driver = ApplicationContext::getContainer()->get(DriverFactory::class)->get('iot-event');
//            $driver->push(new IotEvent($fd, 'remote_stop_response', [
//                'charger_id' => $chargerId,
//                'gun_no' => $gunNo,
//                'order_id' => $orderId,
//                'result' => $result,
//                'result_text' => $resultText
//            ]));

        } catch (\Exception $e) {
            Normal::logger(sprintf(
                "Remote stop response processing error - FD:%d Error:%s Trace:%s",
                $fd,
                $e->getMessage(),
                $e->getTraceAsString()
            ), 'notify-event');
        }
    }

    /**
     * 处理重启响应 (0x0A)
     * 充电桩对运营管理系统重启命令的回复
     */
    private function handleRestartResponse($server, int $fd, string $body, int $seq): void
    {
        try {
            if (strlen($body) < 9) {
                Normal::logger(sprintf(
                    "Invalid RestartResponse - FD:%d Body too short (%d bytes)",
                    $fd,
                    strlen($body)
                ), 'notify-event');
                return;
            }

            // 1. 获取桩编号的二进制数据（8字节）
            $binaryChargerId = substr($body, 0, 8);

            // 2. 解析为字符串（统一使用 parseChargerId 方法）
            $chargerId = $this->parseChargerId($binaryChargerId);

            // 3. 解析结果
            $result = ord($body[8]);

            $resultText = match($result) {
                0 => '准备重启',
                1 => '重启失败',
                default => '未知结果'
            };

            // 4. 记录响应信息
            Normal::logger(sprintf(
                "RestartResponse - FD:%d ID:%s Result:%d(%s)",
                $fd,
                $chargerId,
                $result,
                $resultText
            ), 'notify-event');

            // 5. 异步处理重启响应业务
            $driver = ApplicationContext::getContainer()->get(DriverFactory::class)->get('iot-event');
            $driver->push(new IotEvent($fd, 'restart_response', [
                'charger_id' => $chargerId,
                'result' => $result,
                'result_text' => $resultText
            ]));

        } catch (\Exception $e) {
            Normal::logger(sprintf(
                "Process RestartResponse error - FD:%d Error:%s Trace:%s",
                $fd,
                $e->getMessage(),
                $e->getTraceAsString()
            ), 'notify-event');
        }
    }

    /**
     * 处理设备参数设置响应 (0x0D)
     * 充电桩对运营管理系统设备参数设置命令的回复
     */
    private function handleDeviceParameterResponse($server, int $fd, string $body, int $seq): void
    {
        try {
            if (strlen($body) < 9) {
                Normal::logger(sprintf(
                    "Invalid DeviceParameterResponse - FD:%d Body too short (%d bytes)",
                    $fd,
                    strlen($body)
                ), 'notify-event');
                return;
            }

            // 解析桩编号 (使用BCD格式)
            $chargerId = $this->parseChargerId($body);

            // 解析设置结果
            $result = ord($body[8]);

            $resultText = match($result) {
                0 => '设置成功',
                1 => '设置失败',
                default => '未知结果'
            };

            // 记录响应信息
            Normal::logger(sprintf(
                "DeviceParameterResponse - FD:%d ID:%s Result:%d(%s)",
                $fd,
                $chargerId,
                $result,
                $resultText
            ), 'notify-event');

        } catch (\Exception $e) {
            Normal::logger(sprintf(
                "Process DeviceParameterResponse error - FD:%d Error:%s Trace:%s",
                $fd,
                $e->getMessage(),
                $e->getTraceAsString()
            ), 'notify-event');
        }
    }

    /**
     * 处理设备参数读取响应 (0x0C)
     * 充电桩对运营管理系统设备参数读取命令的回复
     */
    private function handleDeviceParameterReadResponse($server, int $fd, string $body, int $seq): void
    {
        try {
            if (strlen($body) < 24) { // 8字节桩编号 + 16字节参数
                Normal::logger(sprintf(
                    "Invalid DeviceParameterReadResponse - FD:%d Body too short (%d bytes)",
                    $fd,
                    strlen($body)
                ), 'notify-event');
                return;
            }

            // 解析桩编号 (使用BCD格式)
            $chargerId = $this->parseChargerId(substr($body, 0, 8));

            // 解析各项参数
            $heartbeatInterval = unpack('n', substr($body, 8, 2))[1];     // 心跳间隔(秒)
            $statusReportInterval = unpack('n', substr($body, 10, 2))[1]; // 状态上报间隔(秒)
            $floatChargePower = unpack('n', substr($body, 12, 2))[1];     // 浮充功率(瓦)
            $floatChargeTime = unpack('n', substr($body, 14, 2))[1];      // 浮充时间(秒)
            $zeroPowerTime = unpack('n', substr($body, 16, 2))[1];        // 功率为零时间(秒)
            $singleMaxPower = unpack('n', substr($body, 18, 2))[1];       // 单路最大功率(瓦)
            $totalMaxPower = unpack('n', substr($body, 20, 2))[1];        // 整机最大功率(瓦)
            $maxChargeTime = unpack('n', substr($body, 22, 2))[1];        // 最大充电时长(秒)

            // 记录响应信息
            Normal::logger(sprintf(
                "DeviceParameterReadResponse - FD:%d ID:%s Heartbeat:%ds StatusReport:%ds FloatPower:%dW FloatTime:%ds ZeroPowerTime:%ds SingleMax:%dW TotalMax:%dW MaxChargeTime:%ds",
                $fd,
                $chargerId,
                $heartbeatInterval,
                $statusReportInterval,
                $floatChargePower,
                $floatChargeTime,
                $zeroPowerTime,
                $singleMaxPower,
                $totalMaxPower,
                $maxChargeTime
            ), 'notify-event');

            // 异步处理设备参数读取响应业务
            $driver = ApplicationContext::getContainer()->get(DriverFactory::class)->get('iot-event');
            $driver->push(new IotEvent($fd, 'device_parameter_read_response', [
                'charger_id' => $chargerId,
                'parameters' => [
                    'heart_cycle' => $heartbeatInterval,
                    'report_cycle' => $statusReportInterval,
                    'full_charge_power' => $floatChargePower,
                    'full_charge_delay' => $floatChargeTime,
                    'null_charge_delay' => $zeroPowerTime,
                    'single_max_power' => $singleMaxPower,
                    'total_max_power' => $totalMaxPower,
                    'max_charge_time' => $maxChargeTime
                ]
            ]));

        } catch (\Exception $e) {
            Normal::logger(sprintf(
                "Process DeviceParameterReadResponse error - FD:%d Error:%s Trace:%s",
                $fd,
                $e->getMessage(),
                $e->getTraceAsString()
            ), 'notify-event');
        }
    }

    /**
     * 处理电池状态信息上报 (0x0E)
     */
    private function handleBatteryStatus($server, int $fd, string $body, int $seq): void
    {
        try {
            if (strlen($body) < 16) {
                Normal::logger(sprintf(
                    "Invalid BatteryStatus - FD:%d Body too short (%d bytes)",
                    $fd,
                    strlen($body)
                ), 'notify-event');
                return;
            }

            // 1. 获取桩编号的二进制数据（8字节）
            $binaryChargerId = substr($body, 0, 8);

            // 2. 解析为字符串
            $chargerId = $this->parseChargerId($binaryChargerId);

            // 3. 解析其他字段
            $gunNo = ord($body[8]);
            $batteryVoltage = unpack('n', substr($body, 9, 2))[1] / 100;      // 当前电池电压 (0.01V)
            $requiredVoltage = unpack('n', substr($body, 11, 2))[1] / 100;    // 电池需求电压 (0.01V)
            $requiredCurrent = unpack('n', substr($body, 13, 2))[1] / 100;    // 电池需求电流 (0.01A)
            $chargeVoltage = unpack('n', substr($body, 15, 2))[1] / 100;      // 充电电压测量值 (0.01V)
            $chargeCurrent = ord($body[17]) / 100;                            // 充电电流测量值 (0.01A)
            $soc = unpack('n', substr($body, 18, 2))[1];                      // 当前荷电状态SOC (1%)
            $maxTemperature = ord($body[20]) - 50;                            // 当前蓄电池组最高温度 (-50偏移量)
            $maxCellVoltage = unpack('n', substr($body, 21, 2))[1] / 100;     // 最高单体电压 (0.01V)

            // 4. 记录电池状态信息
            Normal::logger(sprintf(
                "BatteryStatus - FD:%d ID:%s Gun:%d BatteryVoltage:%.2fV RequiredVoltage:%.2fV RequiredCurrent:%.2fA ".
                "ChargeVoltage:%.2fV ChargeCurrent:%.2fA SOC:%d%% MaxTemperature:%d℃ MaxCellVoltage:%.2fV",
                $fd,
                $chargerId,
                $gunNo,
                $batteryVoltage,
                $requiredVoltage,
                $requiredCurrent,
                $chargeVoltage,
                $chargeCurrent,
                $soc,
                $maxTemperature,
                $maxCellVoltage
            ), 'notify-event');

            // 5. 构造响应包 (0x8F)
            $responseBody = $binaryChargerId . chr($gunNo);
            $response = $this->buildResponse(0x8F, $seq, $responseBody);
            $server->send($fd, $response);

            // 6. 异步处理电池状态信息
            $driver = ApplicationContext::getContainer()->get(DriverFactory::class)->get('iot-event');
            $driver->push(new IotEvent($fd, 'battery_status', [
                'charger_id' => $chargerId,
                'port_bin' => $gunNo,
                'battery_volt' => $batteryVoltage,
                'required_volt' => $requiredVoltage,
                'required_curr' => $requiredCurrent,
                'charge_volt' => $chargeVoltage,
                'charge_curr' => $chargeCurrent,
                'soc' => $soc,
                'max_temperature' => $maxTemperature,
                'max_cell_volt' => $maxCellVoltage
            ]));

        } catch (\Exception $e) {
            Normal::logger(sprintf(
                "Battery status processing error - FD:%d Error:%s Trace:%s",
                $fd,
                $e->getMessage(),
                $e->getTraceAsString()
            ), 'notify-event');
        }
    }

    /**
     * 启动连接诊断功能
     */
    public static function startDiagnostics(SwooleServer $server): void
    {
        // 清理之前的定时器（如果存在）
        if (self::$diagnosticTimerId !== null) {
            Timer::clear(self::$diagnosticTimerId);
        }

        if (self::$cleanupTimerId !== null) {
            Timer::clear(self::$cleanupTimerId);
        }

        // 每分钟记录一次连接诊断信息
        self::$diagnosticTimerId = Timer::tick(60000, function () use ($server) {
            $now = microtime(true);
            $stats = $server->stats();

            // 限制诊断信息中记录的连接数，避免日志过大
            $connections = [];
            $count = 0;
            foreach (self::$connections as $fd => $conn) {
                // 只记录活跃连接或异常连接
                $inactiveTime = $now - $conn['last_activity'];
                $duration = $now - $conn['connect_time'];

                // 记录连接时间超过1分钟或者不活跃时间超过5分钟的连接
                if ($duration > 60 || $inactiveTime > 300 || $conn['state'] !== self::STATE_CONNECTED) {
                    $connections[] = [
                        'fd' => $fd,
                        'state' => $conn['state'],
                        'duration' => round($duration, 2),
                        'inactive' => round($inactiveTime, 2),
                        'ip' => $conn['remote_ip'],
                        'charger_id' => $conn['charger_id'] ?? 'unknown'
                    ];

                    $count++;
                    // 限制记录的连接数，避免日志过大
                    if ($count >= 100) {
                        $connections[] = ['message' => 'More connections exist, limit reached'];
                        break;
                    }
                }
            }

            // 记录系统资源
            $load = sys_getloadavg();
            $memory = memory_get_usage(true) / 1024 / 1024;
            $connectionsCount = count(self::$connections);

            Normal::logger(sprintf(
                "Diagnostics - Connections:%d/%d Load:%.2f,%.2f,%.2f Memory:%.2fMB Details:%s",
                $connectionsCount,
                $stats['connection_num'] ?? 0,
                $load[0], $load[1], $load[2],
                $memory,
                json_encode($connections, JSON_UNESCAPED_UNICODE)
            ), 'diagnostics');
        });

        // 每30分钟清理一次过期连接信息
        self::$cleanupTimerId = Timer::tick(1800000, function () {
            self::cleanupStaleConnections();
        });
    }

    /**
     * 清理过期连接信息（防止内存泄漏）
     */
    public static function cleanupStaleConnections(): void
    {
        $now = microtime(true);
        $staleCount = 0;

        foreach (self::$connections as $fd => $conn) {
            // 如果连接标记为已关闭且超过5分钟未清理，则强制清理
            if ($conn['state'] === self::STATE_CLOSED &&
                ($now - $conn['connect_time']) > 300) {
                unset(self::$connections[$fd]);
                unset(self::$buffer[$fd]); // 同时清理缓冲区
                $staleCount++;
            }

            // 如果连接超过24小时，可能是异常连接，也进行清理
            if (($now - $conn['connect_time']) > 86400) {
                unset(self::$connections[$fd]);
                unset(self::$buffer[$fd]); // 同时清理缓冲区
                $staleCount++;
                Normal::logger(sprintf(
                    "Force cleanup of long-lived connection - FD:%d Duration:%.2fs",
                    $fd,
                    $now - $conn['connect_time']
                ), 'notify-event');
            }
        }

        if ($staleCount > 0) {
            Normal::logger(sprintf(
                "Cleaned up %d stale connections",
                $staleCount
            ), 'notify-event');
        }
    }
}
